package org.extreme.web.core.ctrl;

import java.lang.reflect.Method;
import java.lang.reflect.Modifier;
import java.util.ArrayList;
import java.util.List;

import org.extreme.web.core.action.ActionException;
import org.extreme.web.core.action.Can;
import org.extreme.web.core.action.CtrlAction;
import org.extreme.web.core.action.IAction;
import org.extreme.web.core.aop.ActionInvoker;
import org.extreme.web.core.aop.Aop;
import org.extreme.web.core.aop.Interceptor;
import org.extreme.web.core.aop.InterceptorStack;
import org.extreme.web.core.cfg.WebGlobal;
import org.extreme.web.core.cfg.Methods;
import org.extreme.web.core.env.Env;

import com.alibaba.fastjson.JSON;

public abstract class AbstractCtrl implements ICtrl{
	
	private String path;
	
	@Override
	public List<IAction> toActions(){
		Class<?> claz = getClass();
		Aop aop = claz.getAnnotation(Aop.class);
		InterceptorStack stack = new InterceptorStack();
		try{
			Class<? extends Interceptor>[] ins = aop.value();
			for(Class<? extends Interceptor> i :ins){
				stack.add(i.newInstance());//加入控制器级别的拦截器
			}
		}catch(Exception e){
			e.printStackTrace();
			throw new ActionException("resolve ctrl annotation err.");
		}
		Method[] methods = claz.getMethods();
		List<IAction> list = new ArrayList<IAction>();
		for(Method m : methods){
			//只有void返回值，public，并且没有参数，才会被视为一个action方法
			int modifiers = m.getModifiers();
			boolean isVoid = (m.getReturnType()==void.class);
			boolean isPublic = (Modifier.isPublic(modifiers));
			boolean notFinal = !(Modifier.isFinal(modifiers));
			boolean notNative = !(Modifier.isNative(modifiers));
			boolean isNoneParam = (m.getParameterTypes().length==0);
			if(isVoid && isPublic && isNoneParam && notFinal && notNative){
				

				
				ActionInvoker invoker = new ActionInvoker();
				
				Aop m_aop = m.getAnnotation(Aop.class);
				
				try{
					Class<? extends Interceptor>[] m_ins = m_aop.value();
					for(Class<? extends Interceptor> m_i :m_ins){
						stack.add(m_i.newInstance());
					}
				}catch(Exception e){
					e.printStackTrace();
					throw new ActionException("resolve ctrl annotation err.");
				}
				
				String actionKey;
				if(WebGlobal.INDEX_METHOD_NAME.equals(m.getName())){
					actionKey = getPath();
				}else{
					actionKey = getPath()+"/"+m.getName();
				}
				
				CtrlAction action = new CtrlAction(this, m,getCanMethods(m), actionKey);
				list.add(action);
				invoker.setStack(stack);
				invoker.setAction(action);
				action.setInvoker(invoker);
			}
		}
		return list;
	}

	@Override
	public String getPath() {
		return path;
	}
	
	@Override
	public void setPath(String path){
		this.path = path;
	}
	
	public void render(String view){
		WebGlobal.getDefaultRender().render(view);
	}
	
	public void renderStr(String str){
		WebGlobal.getDefaultRender().renderStr(str);
	}
	
	public void setAttr(String key, Object value){
		Env.req().setAttribute(key, value);
	}
	
	@SuppressWarnings("unchecked")
	public <T> T getAttr(String key){
		return (T)Env.req().getAttribute(key);
	}
	
	public Object getAttrObj(String key){
		return Env.req().getAttribute(key);
	}
	
	/**
	 * get surpport methods,if none annotation then return all methods
	 * @param m
	 * @return
	 */
	protected String[] getCanMethods(Method m){
		Can c = m.getAnnotation(Can.class);
		if(c==null) return Methods.ALL_METHODS;
		String[] methods = c.value();
		return methods;
	}
	
	public void renderJson(Object obj){
		renderStr(JSON.toJSONString(obj));
	}
}
